// -*- encoding: utf-8 -*-
/*
    Filename         :main.c
    Description      :main operation
    Time             :2021/04/24 22:20:11
    Author           :LoanCold
*/


#include <stdlib.h>
#include <stdio.h>
#include "extmem.h"
#include "defines.h"
#include "database.c"


int main(int argc, char **argv)
{
    Buffer buf; /* A buffer */

    /* Initialize the buffer */
    if (!initBuffer(520, 64, &buf))
    {
        perror("Buffer Initialization Failed!\n");
        return -1;
    }

    // Indicates the start and end result blk num of each question
    // array[2] indicates io
    int Q1_linear_search[3]={0,0};
    int Q2_R_twostage_multiway_merge_sort[3]={0,0};
    int Q2_S_twostage_multiway_merge_sort[3]={0,0};
    int Q3_index[3]={0,0};
    int Q3_index_sort[3]={0,0};
    int Q4_sort_merge_join[3]={0,0};
    int Q5_sort_merge_union[3]={0,0};
    int Q5_sort_merge_intersection[3]={0,0};
    int Q5_sort_merge_minus[3]={0,0};

    printf("///////////////////////////////////////////////////////////\n"
    "////////Q1 select S.C, S.D from S where S.C = 50///////////\n"
    "///////////////////////////////////////////////////////////\n");
    ///将块17-48的关系S取出，选择之后的结果放在块49及之后
    
    unsigned char *blk_s, *blk_result;
    int b_s=SIZE_R+1;// num of block in relative s
    int b_result=SIZE_R+SIZE_S+1;// num of block in relative result
    int p_s,p_result;// pointer to blk s/result
    unsigned char value_c[3]; // value of C in relative S
    blk_result = getNewBlockInBuffer(&buf);
    p_s = 0;
    p_result = 0;
    printf("Q1 Start: First result block %d\n",b_result);
    for(b_s = SIZE_R+1; b_s<=SIZE_R+SIZE_S; b_s++){
        blk_s = readb(b_s, &buf);
        for(p_s=0; p_s < MAX_TUPLE_PBLK; p_s++){
            // get value C in tuple from s
            if(get_value(get_turple_addr(p_s, blk_s), 0) == 50){
                // result blk full: write to disk and clear 
                check_result_blk_full(&p_result, &b_result, &blk_result, &buf);
                turple_cpy(get_turple_addr(p_result, blk_result), get_turple_addr(p_s, blk_s));
                p_result++;
            }
        }
        freeBlockInBuffer(blk_s, &buf);
    }
    // write last result buf to disk
    write_lastblk(b_result, 0,blk_result, &buf);
    printf("Q1 finished: Last result block %d\n",b_result);
    Q1_linear_search[0] = SIZE_R+SIZE_S+1;
    Q1_linear_search[1] = b_result;
    Q1_linear_search[2] = buf.numIO;
    b_result++;//move to next block



    printf("///////////////////////////////////////////////////////////\n"
    "//////////////Q2: 两阶段多路归并降序排序： R.A S.C///////////\n"
    "///////////////////////////////////////////////////////////\n");
    printf("Q2 Start: First result block %d\n",b_result);

    unsigned char *tmpbuf[MAX_BUF_NUM];
    int b_result_s;
    // it is both used for relative S and R. So we choose bigger one: MEM_R
    unsigned char* buf_s[MEM_S];// which way in S
    int p_buf[MEM_S];// which tuple in blk
    int b_buf[MEM_S];// which blk in ways

    // Relative R
    b_result_s = sub_sort(MEM_R, 0, b_result, &buf);
    printf("Q2 Relative S: Sub sort last result block %d\n",b_result_s-1);
    for(int i=0; i<MEM_R; i++){
        p_buf[i] = 0;
        b_buf[i] = b_result+ i*MAX_BUF_NUM;
        buf_s[i] = readb(b_buf[i], &buf);
    }
    Q2_R_twostage_multiway_merge_sort[0] = b_result + SIZE_R;
    b_result = multiway_mergesort(MEM_R, b_result, p_buf, b_buf, buf_s, &buf) +1 ;
    Q2_R_twostage_multiway_merge_sort[1] = b_result-1;
    Q2_R_twostage_multiway_merge_sort[2] = buf.numIO;
    printf("Q2 Relative R: Merge sort last block %d\n",b_result-1);
    
    // Relative S
    b_result_s = sub_sort(MEM_S, SIZE_R, b_result, &buf);
    printf("Q2 Relative S: Sub sort last result block %d\n",b_result_s-1);
    for(int i=0; i<MEM_S; i++){
        p_buf[i] = 0;
        b_buf[i] = b_result+ i*MAX_BUF_NUM;
        buf_s[i] = readb(b_buf[i], &buf);
    }

    Q2_S_twostage_multiway_merge_sort[0] = b_result + SIZE_S;
    b_result = multiway_mergesort(MEM_S, b_result, p_buf, b_buf, buf_s, &buf) +1 ;
    Q2_S_twostage_multiway_merge_sort[1] = b_result-1;
    printf("Q2 Relative S: Merge sort last block %d\n",b_result-1);
    Q2_S_twostage_multiway_merge_sort[2] = buf.numIO;
    
    

    printf("///////////////////////////////////////////////////////////\n"
    "////////////////Q3: 基于索引的关系选择： S.C/////////////////\n"
    "///////////////////////////////////////////////////////////\n");
    printf("Q3 Start: First result block %d\n",b_result);

    int begin = Q2_S_twostage_multiway_merge_sort[0];
    int end = Q2_S_twostage_multiway_merge_sort[1];
    p_result = 0;
    b_result_s = b_result;
    blk_result = getNewBlockInBuffer(&buf);
    clear_buffer(blk_result);
    // index:(first C value, blk num)
    for(; begin<=end; begin++){
        blk_s = readb(begin, &buf);
        freeBlockInBuffer(blk_s, &buf);
        check_result_blk_full(&p_result, &b_result_s, &blk_result, &buf);
        turple_cpy(get_turple_addr(p_result, blk_result), blk_s);
        // change (S.C, S.D) -> (S.C, blk num)
        itoa(get_turple_addr(p_result, blk_result) + BYTES_VALUE, begin);
        p_result++;
    }
    Q3_index[0] = b_result;
    Q3_index[1] = b_result_s;
    Q3_index[2] = buf.numIO;
    b_result = b_result_s + 1;
    write_lastblk(Q3_index[1], 0, blk_result, &buf);
    printf("Q3 Index constructed: last blk num %d\n", Q3_index[1]);


    // Select through index
    int pre_blk_num = Q2_S_twostage_multiway_merge_sort[0];
    int pre_value = 99999;
    int now_value;
    begin = Q3_index[0];
    end = Q3_index[1];
    p_result = 0;
    for(;begin<= end; begin++){
        blk_s = readb(begin, &buf);
        for(p_s=0; p_s < MAX_TUPLE_PBLK; p_s++){
            // get value C in tuple from s
            now_value = get_value(blk_s + p_s*8, 0);
            if(pre_value>50 && now_value<=50){
                break;
            }
            pre_blk_num = get_value(blk_s + p_s*8, 1);
            pre_value = now_value;
        }
        freeBlockInBuffer(blk_s, &buf);
    }
    printf("Q3 Index sort: find target blk num %d\n",pre_blk_num);
    
    p_result = 0;
    b_result_s = b_result;
    blk_result = getNewBlockInBuffer(&buf);
    // from pre_blk_num to find value less than 50
    while(1){
        int value;
        blk_s = readb(pre_blk_num++, &buf);
        for(p_s=0; p_s < MAX_TUPLE_PBLK; p_s++){
            // get value C in tuple from s
            value = get_value(get_turple_addr(p_s, blk_s), 0);\
            if(value == 50){
                // result blk full: write to disk and clear 
                check_result_blk_full(&p_result, &b_result, &blk_result, &buf);
                turple_cpy(get_turple_addr(p_result, blk_result), get_turple_addr(p_s, blk_s));
                p_result++;
            }
            // <50: stop searching
            if(value< 50){
                break;
            }
        }
        if(value< 50){
            break;
        }
        freeBlockInBuffer(blk_s, &buf);
    }
    write_lastblk(b_result, 0, blk_result, &buf);
    Q3_index_sort[0] = b_result_s;
    Q3_index_sort[1] = b_result++;
    Q3_index_sort[2] = buf.numIO;

    printf("///////////////////////////////////////////////////////////\n"
    "////////////////Q4: 实现基于排序的连接操作算法：R.A S.C/////////////////\n"
    "///////////////////////////////////////////////////////////\n");

    Q4_sort_merge_join[0] = b_result;
    b_result = multiway_sort_merge(Q2_R_twostage_multiway_merge_sort[0],
                        Q2_S_twostage_multiway_merge_sort[0],
                        b_result, &buf);
    Q4_sort_merge_join[1] = b_result++;
    Q4_sort_merge_join[2] = buf.numIO;
    
    printf("///////////////////////////////////////////////////////////\n"
    "////////////////Q5: 基于排序或散列的两趟扫描算法：S交R/////////////////\n"
    "///////////////////////////////////////////////////////////\n");

    printf("now union");

    Q5_sort_merge_union[0] = b_result;
    b_result = multiway_sort_union(Q2_R_twostage_multiway_merge_sort[0],
                        Q2_S_twostage_multiway_merge_sort[0],
                        b_result, &buf);
    Q5_sort_merge_union[1] = b_result++;
    Q5_sort_merge_union[2] = buf.numIO;
    
    printf("///////////////////////////////////////////////////////////\n"
    "////////////////Q5: 基于排序或散列的两趟扫描算法：S并R/////////////////\n"
    "///////////////////////////////////////////////////////////\n");

    Q5_sort_merge_intersection[0] = b_result;
    b_result = multiway_sort_intersection(Q2_R_twostage_multiway_merge_sort[0],
                        Q2_S_twostage_multiway_merge_sort[0],
                        b_result, &buf);
    Q5_sort_merge_intersection[1] = b_result++;
    Q5_sort_merge_intersection[2] = buf.numIO;

    printf("///////////////////////////////////////////////////////////\n"
    "////////////////Q5: 基于排序或散列的两趟扫描算法：S-R/////////////////\n"
    "///////////////////////////////////////////////////////////\n");

    Q5_sort_merge_minus[0] = b_result;
    b_result = multiway_sort_minus(Q2_R_twostage_multiway_merge_sort[0],
                        Q2_S_twostage_multiway_merge_sort[0],
                        b_result, &buf);
    Q5_sort_merge_minus[1] = b_result++;
    Q5_sort_merge_minus[2] = buf.numIO;


    printf("///////////////////////////////////////////////////////////\n"
    "//////////////////Result: 最终结果地址总结///////////////////\n"
    "///////////////////////////////////////////////////////////\n");
    Q5_sort_merge_minus[2] -=               Q5_sort_merge_intersection[2];
    Q5_sort_merge_intersection[2] -=        Q5_sort_merge_union[2];
    Q5_sort_merge_union[2] -=               Q4_sort_merge_join[2];
    Q4_sort_merge_join[2] -=                Q3_index_sort[2];
    Q3_index_sort[2] -=                     Q3_index[2];
    Q3_index[2] -=                          Q2_S_twostage_multiway_merge_sort[2];
    Q2_S_twostage_multiway_merge_sort[2] -= Q2_R_twostage_multiway_merge_sort[2];
    Q2_R_twostage_multiway_merge_sort[2] -= Q1_linear_search[2];


    printf("Q1 Linear Search : Block num (%d-%d)  IO %d\n"      ,Q1_linear_search[0]    ,Q1_linear_search[1],Q1_linear_search[2]);
    printf("Q2 TPMMS : Relative R Block num (%d-%d)  IO %d\n"   ,Q2_R_twostage_multiway_merge_sort[0],Q2_R_twostage_multiway_merge_sort[1],Q2_R_twostage_multiway_merge_sort[2]);
    printf("Q2 TPMMS : Relative S Block num (%d-%d)  IO %d\n"   ,Q2_S_twostage_multiway_merge_sort[0],Q2_S_twostage_multiway_merge_sort[1],Q2_S_twostage_multiway_merge_sort[2]);
    printf("Q3 Index Sort : Index Block num (%d-%d)  IO %d \n"  ,Q3_index[0],Q3_index[1],Q3_index[2]);
    printf("Q3 Index Sort : Result Block num (%d-%d)  IO %d\n"  ,Q3_index_sort[0],Q3_index_sort[1],Q3_index_sort[2]);
    printf("Q4 Sort merge join : Block num (%d-%d)  IO %d\n"    ,Q4_sort_merge_join[0],Q4_sort_merge_join[1],Q4_sort_merge_join[2]);
    printf("Q5 Sort merge union : Block num (%d-%d)  IO %d\n"   ,Q5_sort_merge_union[0],Q5_sort_merge_union[1],Q5_sort_merge_union[2]);
    printf("Q5 Sort merge intersection : Block num (%d-%d)  IO %d\n",Q5_sort_merge_intersection[0],Q5_sort_merge_intersection[1],Q5_sort_merge_intersection[2]);
    printf("Q5 Sort merge minus : Block num (%d-%d)  IO %d\n"   ,Q5_sort_merge_minus[0],Q5_sort_merge_minus[1],Q5_sort_merge_minus[2]);


    return 0;
}

